package org.fujene.sandbox;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.Executor;

import org.msgpack.MessagePackObject;
import org.msgpack.object.ArrayType;
import org.msgpack.object.IntegerType;
import org.msgpack.object.RawType;
import org.msgpack.rpc.Client;
import org.msgpack.rpc.Request;
import org.msgpack.rpc.Server;
import org.msgpack.rpc.loop.EventLoop;

import junit.framework.TestCase;

public class TestSocket extends TestCase {
	public static void testConnect() throws IOException {
		new Executor() {
			@Override
			public void execute(Runnable command) {
				new Thread(command).start();
			}
		}.execute(new connectRPCServer());

		new Executor() {
			@Override
			public void execute(Runnable command) {
				new Thread(command).run();
			}
		}.execute(new connectRPCClient());
	}

	public static class connectServerClass implements Runnable {
		@Override
		public void run() {
			ServerSocket svrsock = null;
			Socket sock = null;

			try {
				svrsock = new ServerSocket(61000);
				System.out.println("Server port 61000 started.");
				sock = svrsock.accept();
				System.out.println("Connection accepted.");

				BufferedReader br = new BufferedReader(new InputStreamReader(
						sock.getInputStream()));
				BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
						sock.getOutputStream()));

				String line = null;
				while (true) {
					line = br.readLine();
					if (line.equals("q"))
						break;
					System.out.println(line);
					System.out.println("Server gets: " + line);

					bw.write(line);
				}
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					if (sock != null) {
						sock.close();
					}
					if (svrsock != null) {
						svrsock.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

	}

	public static class connectClientClass implements Runnable {
		@Override
		public void run() {
			Socket sock = null;

			try {
				sock = new Socket("localhost", 61000);

				System.out.println("Socket connecting...");

				BufferedReader br = new BufferedReader(new InputStreamReader(
						sock.getInputStream()));
				BufferedReader ir = new BufferedReader(new InputStreamReader(
						System.in));
				// BufferedWriter bw = new BufferedWriter(new
				// OutputStreamWriter(
				// sock.getOutputStream()));
				DataOutputStream os = new DataOutputStream(
						sock.getOutputStream());

				String line = null;
				while (true) {
					System.out.print("Input string -> ");
					line = ir.readLine();
					// bw.write(line);
					os.writeBytes(line);
					if (line.equals("q"))
						break;
					line = br.readLine();
					System.out.println("Client recieves: " + line);
				}
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				try {
					if (sock != null)
						sock.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public static class RPCHandler {
		public void hello(Request request) {
			// 引数取り出し
			MessagePackObject obj = request.getArguments();
			MessagePackObject[] args = obj.asArray();
			byte[] str = args[0].asByteArray();
			System.out
					.println("Sending byte succeeded. length = " + str.length);
			long time = args[1].asLong();
			System.out.println("Time: " + ((System.nanoTime() - time)/1000000.0));

			request.sendResult(ArrayType.create(new MessagePackObject[] {
					RawType.create(new byte[1000000]),
					IntegerType.create(System.nanoTime()) }));
		}
	}

	public static class connectRPCServer implements Runnable {
		@Override
		public void run() {
			Server server = new Server(EventLoop.defaultEventLoop());

			try {
				server.serve(new RPCHandler());
				server.listen(61000);
				while (true) {
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public static class connectRPCClient implements Runnable {
		@Override
		public void run() {
			try {
				Client client = new Client("127.0.0.1", 61000);

				MessagePackObject result = client.callApply("hello",
						new Object[] { new byte[1000000], System.nanoTime() });
				MessagePackObject[] objs = result.asArray();
				
				System.out.println("Recieving byte succeeded. length = "
						+ objs[0].asByteArray().length);
				System.out.println("Time: " + ((System.nanoTime() - objs[1].asLong())/1000000.0));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}
